书籍地址
https://www.safaribooksonline.com/library/view/developing-nodejs-applications/9780738442853/

1. 创建一个hello world应用

http://bluemix.net/
创建账号并登陆

进入控制台

选择nodejs SDK

创建node应用

使用持续交付工具链

git仓库类型选择new

选择Eclipse Orion Web IDE

编写代码

根/vy102-qqq-nodejs/currentDate/lib/currentDate.js

1
2
3
exports.currentDateTime = function() {
return Date();
};

根/vy102-qqq-nodejs/currentDate/package.json

1
2
3
4
{
"name": "currentDate",
"main": "./lib/currentDate"
}

根/vy102-qqq-nodejs/app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var http = require("http");
var dateModule = require('./currentDate');

// Read the port from the underlying environment.
// If not exist, use the default port: 8080
var port = process.env.VCAP_APP_PORT || 8080;

// Create the server and listen to requests on the specified port.
http.createServer(function (request, response) {
// Set the content type of the response
response.writeHead(200, {'Content-Type': 'text/plain'});
// Write a simple Hello World message,
// Write a simple Hello World message appended with the current date
response.end('Hello NodeJS! The time now is: ' + dateModule.currentDateTime());
}).listen(port);

根/vy102-qqq-nodejs/package.json

1
2
3
4
5
6
7
8
{
"name": "NodejsStarterApp",
"version": "0.0.1",
"description": "A Hello World NodeJS sample",
"scripts": {
"start": "node app.js"
}
}

根/vy102-qqq-nodejs/manifest.yml

1
2
3
4
5
6
7
8
applications:
- path: .
memory: 256M
instances: 1
domain: au-syd.mybluemix.net
name: vy102-qqq-nodejs
host: vy102-qqq-nodejs
disk_quota: 1024M

创建配置项

运行项目

2. Understanding asynchronous callback

Watson Language Translator
https://language-translator-demo.ng.bluemix.net/

与nodejs sdk操作相同,在控制台搜索language translator并添加。

orion编译器里,编辑启动配置,绑定服务

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*eslint-disable no-unused-params */
var http = require("http");
const translatorModule = require('./translator');

var helloText = 'Hello';
var fromLanguage = 'en';
var toLanguage = 'es';

var portNumber = process.env.VCAP_APP_PORT || 8080;
const server = http.createServer(handleRequests);
server.listen(portNumber, function () {
console.log('Server is up!');
});

function handleRequests(userRequest, userResponse) {
userResponse.writeHead(200, {
'Content-Type': 'text/plain'
});

var callback = function (error, translatorOutput) {
if (error) {
userResponse.end(error);
} else {
userResponse.end('Translation of ' + helloText + " is " + translatorOutput);
}

};

translatorModule.getTranslation(helloText, fromLanguage, toLanguage, callback);
}

translator/lib/translator.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//const watson = require('watson-developer-cloud');
var LanguageTranslatorV3 = require('watson-developer-cloud/language-translator/v3');


exports.getTranslation = function getTranslation(helloText, fromLanguage, toLanguage, callback) {
var language_translator = new LanguageTranslatorV3({
version: '2018-05-01',
iam_apikey: 'zODif6DVPCj-sQOlydcaq4Wqfx3cVr_oTjZjznplbpXi',
url: 'https://gateway-syd.watsonplatform.net/language-translator/api'
});

var translatorCallback = function (err, data) {

if (err) {
console.log(err);
callback(err, null);
} else {
console.log(data);
callback(null, data.translations[0].translation);
}
};


language_translator.translate({
text: helloText,
source: fromLanguage,
target: toLanguage
}, translatorCallback);

};

3. Creating your first Express application

https://github.com/ibm-redbooks-dev/vy102-XXX-express

Watson Natural Language Understanding service
https://console.bluemix.net/apidocs/natural-language-understanding?language=node

package.json

1
2
3
4
5
6
7
8
9
10
{
"name": "vy102-qqq-nodejs",
"version": "0.0.1",
"description": "A sample express app",
"dependencies": {
"express": "4.16.4",
"body-parser": "1.18.3",
"watson-developer-cloud": "3.13.0"
}
}

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var port = process.env.VCAP_APP_PORT || 8080;
//Express Web Framework, and create a new express server
var express = require('express'),
app = express();
var bodyParser = require('body-parser');

//Routes modules
var index = require('./routes'),
author = require('./routes/author');

//parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({
extended: false
}));

//In case the caller access any URI under the root /, call index route
app.use('/', index);

//In case the caller access any URI under /author, call author route
app.use('/author', author);


// start server on the specified port and binding host
app.listen(port);

views/index.html

1
2
3
4
5
6
7
8
9
10
11
12
<html>

<body>
<h1 style="color:blue;">Watson Author Finder</h1>
<p>To get information about the author of an article, enter the URL of that article.</p>
<form action="author" method="post">
<input type="text" name="url" />
<input type="submit" value="Submit" />
</form>
</body>

</html>

services/articleServices.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Watson Natural Language Understanding third party module
//Specify the release for the Natural Language Understanding service
var NaturalLanguageUnderstandingV1 = require('watson-developer-cloud/natural-language-understanding/v1.js');
var natural_language_understanding = new NaturalLanguageUnderstandingV1({
'version_date': NaturalLanguageUnderstandingV1.VERSION_DATE_2017_02_27,
iam_apikey: 'hySqyRqhRmlCaUeMlxF8Sk29T8ovIGzkFYOfVZH33oPQ',
url: 'https://gateway-syd.watsonplatform.net/natural-language-understanding/api'
});

//error message for missing URL
const MISSING_URL_ERROR = 'URL not passed';

exports.extractArticleAuthorNames = function (req, callback) {

//If the url is not passed, return error to the caller
if (req === null || req.body === null || req.body.url === null) {
callback(MISSING_URL_ERROR, null);
return;
}

// url is the parameter passed in the POST request to /author
// It contains the URL of the article
// The metadata feature returns the author, title, and publication date.
var parameters = {
'url': req.body.url,
'features': {
'metadata': {}
}
};

// Call the Watson service and return the list of authors
natural_language_understanding.analyze(parameters, function (err, response) {
if (err)
callback(err, null);
else
callback(null, response.metadata.authors);
});


};

routes/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
// index.js - Index route module
var express = require('express');
var router = express.Router();

//Provides utilities for dealing with directories
var path = require('path');

// Home page route
router.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../views/index.html'));
});

module.exports = router;

routes/author.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// author.js - Author route module
var express = require('express');
var router = express.Router();
var articleServices = require('../services/articleServices');

router.post('/', function (req, res) {
articleServices.extractArticleAuthorNames(req, function (err, response) {
if (err)
res.status(500).send('error: ' + err);
else
res.send(response);
});
});

module.exports = router;

4. Building a rich front-end application by using React and ES6

react不太了解,先放代码,以后再学习

代码格式化,勾选Support e4x/jsx syntax
https://beautifier.io/

frontend/components/components.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
class Container extends React.Component {
constructor(props) {
super(props);

this.state = {
url: '',
authors: [],
inputVal: ''
};
}

updateUrl(e) {
this.setState({
inputVal: e.target.value
});
}

// getAuthor uses the fetch function to retrieve authors
// from the REST service created in the previous exercise
getAuthor() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
fetch('/author', {
method: 'POST',
body: "url=" + this.state.inputVal,
headers: myHeaders
}).then(res => res.json())
.then(data => this.setState({
authors: data,
url: this.state.inputVal
}));
}

// Render is the core function behind React components.
// It defines components and elements in XML format.
// This is only feasible if using JSPX and Babel JavaScript compiler.
render() {
return (
<div class="jumbotron text-center">
<h1>Author Finder</h1>
<div id='input-form' class='text-center'>
<input type="text" class="form-control input-lg text-center" onChange={e=>this.updateUrl(e)} placeholder="Enter URL of Article here!"/>
</div>
<br/>
<button type="button" class="btn btn-primary btn-lg" disabled = {this.state.inputVal.length===0} onClick={()=>{this.getAuthor()}}>Retrieve Author</button>
<Results url={this.state.url} hide={this.state.authors.length === 0} authors={this.state.authors}/>
</div>
)
}


}

// Results: is another React component
// It creates the list of AuthorRecords
class Results extends React.Component {
constructor(props) {
super(props);
}

render() {

if (this.props.hide) {
return null;
}

return (
<div class='form-inline'>
<div class="row">
<div class="col-xs-12 col-md-3">
<h2>Article URL:</h2>
</div>
<div class="col-xs-12 col-md-9">
{this.props.url}
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-3">
<h2>Authors:</h2>
</div>
<div class="col-xs-12 col-md-9">
<div class="row">
{this.renderAuthors()}
</div>
</div>
</div>
</div>
)
}

/*
Notice the AuthorRecord is defined in a separate file. This is a powerful feature of the React Component: Putting the AuthorRecord in a separate file and making it a reusable component.
*/
renderAuthors() {
/* When developing a component, you should capitalize it.
Hence, you should use "AuthorRecord" instead of "authorrecord" in order to identify it as a component to React.
*/
let authors = this.props.authors;
return authors.map(a => {
return <AuthorRecord author = {a}/>;
});
}

}

ReactDOM.render(<Container />, document.getElementById("root"));

frontend/components/authorrecords.js

1
2
3
4
5
6
7
8
9
10
11
12
13
// AuthorRecord : a component defined to hold author names
class AuthorRecord extends React.Component {

render() {
return (
<div class="row">
<div class="col-xs-12 col-md-6">
{this.props.author.name}
</div>
</div>
);
}
}

frontend/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<html>

<head>
<title>React JS - Author Finder</title>
</head>

<body>
<!-- Loading the script in body is a recommendation to ensure faster loading,
putting all scripts at the header will cause the page to wait till all scripts loaded
Load React related files from internet -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<!-- Load babel JavaScript compiler from internet -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

<script type="text/babel" src="./components/authorrecords.js"></script>
<script type="text/babel" src="./components/components.js"></script>



<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />


<div class="container">
<div class="row">
<!-- You do not need to write much html code, you will
build the whole html on your JSPX code -->
<div class="col-sm-10 col-sm-offset-1 text-center" id="root">
</div>
</div>
</div>
</body>

</html>

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var port = process.env.VCAP_APP_PORT || 8080;
//Express Web Framework, and create a new express server
var express = require('express'),
app = express();
var bodyParser = require('body-parser');

//Routes modules
var author = require('./routes/author');

//Serve the files in /frontend as static files
app.use(express.static(__dirname + '/frontend'));


//parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({
extended: false
}));


//In case the caller access any URI under /author, call author route
app.use('/author', author);


// start server on the specified port and binding host
app.listen(port);